home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / general / procssng / ccs / ccs-11tl.lha / lbl / xview / genial / func / scale.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-07-14  |  5.5 KB  |  194 lines

  1. /*
  2.  * scale.c -- routines to label graphs in an easy-to-read way.
  3.  *            ~antony, 6/16/91
  4.  */
  5.  
  6. #include <stdio.h>
  7. #include <math.h>
  8. #include "scale.h"
  9.  
  10. /* build_glab() builds an array of graph_lab structures for a graph with range
  11.  *  min->max, with up to maxlab labels and of length p_len.
  12.  * p_len is the length in pixels of the display region and is used in
  13.  * construction of the p_off member of the graph_lab structure.
  14.  *
  15.  * build_glab() returns the number of graph_lab structures allocated in the
  16.  * vector pointed to by *lvec, and 0 upon error.
  17.  */
  18.  
  19. /* build_glab() should maintain the min and max which are passed in, and just
  20.  * do 'clean' labelling where possible in between the min and max.
  21.  */
  22.  
  23. int
  24. build_glab(min, max, maxlab, p_len, lvec)
  25.     int       min, max, maxlab, p_len;
  26.     struct graph_lab **lvec;
  27. {
  28.     int       range, order;
  29.     int       start, end;    /* start and end values of intermediate
  30.                  * labels */
  31.     int       nlab;        /* total number of labels */
  32.     int       delta;        /* distance between labels */
  33.     int       val, i;
  34.  
  35.     range = max - min;
  36.     if (range < 1) {
  37. #ifdef DEBUG
  38.     printf("Ranges must be whole numbers.\n");
  39. #endif
  40.     return 0;
  41.     }
  42.     /* order is the order of ten that the range falls into */
  43.     order = (int) exp10(floor(log10((double) range)));
  44.  
  45.     /*
  46.      * now we need to find what type of labelling to do for the points in
  47.      * between min and max based on order and on maxlab.
  48.      */
  49.     /*
  50.      * We will want to find delta, which is a suitable difference between
  51.      * each of the labels.
  52.      */
  53.     if ((delta = opt_div(order, maxlab, range)) < 0) {
  54. #ifdef DEBUG
  55.     printf("error finding the optimal division.\n");
  56. #endif
  57.     return 0;
  58.     }
  59.     /*
  60.      * find the starting point for the first multiple of delta which is
  61.      * greater than min
  62.      */
  63.     start = lmult(delta, min);
  64.     /*
  65.      * find the ending point for the labels:  highest multiple of delta which
  66.      * is less than max
  67.      */
  68.     end = hmult(delta, max);
  69.     /* find the number of labels.  Add 2 for the min and max */
  70.     nlab = (end - start) / delta + 1 + 2;
  71.  
  72.     /* and finally:  allocate space for the labels and fill them in */
  73.     *lvec = (struct graph_lab *) malloc(nlab * sizeof(struct graph_lab));
  74.     if (*lvec == NULL) {
  75.     perror("malloc");
  76.     exit(0);
  77.     }
  78.     /* set the first and last lvec structures appropriately */
  79.     (*lvec)[0].val = min;
  80.     sprintf((*lvec)[0].lab, "%d", (*lvec)[0].val);
  81.     (*lvec)[0].p_off = 0;
  82.     (*lvec)[nlab - 1].val = max;
  83.     sprintf((*lvec)[nlab - 1].lab, "%d", (*lvec)[nlab - 1].val);
  84.     (*lvec)[nlab - 1].p_off = p_len;
  85.  
  86.     /* fill in the labels in between */
  87.     for (val = start; val <= end; val += delta) {
  88.     i = (val - start) / delta + 1;
  89.     (*lvec)[i].val = val;
  90.     sprintf((*lvec)[i].lab, "%d", (*lvec)[i].val);
  91.     (*lvec)[i].p_off = (val - min) * p_len / range;
  92.     }
  93.     return nlab;
  94. }
  95.  
  96. /* opt_div()  Find a good delta for graph labels based on order and maxlab.
  97.    returns: correct delta on success, -1 on error */
  98. /* we could code this to be a bit more general, but there is no compelling
  99.    reason to do so. A more general version might be more compact, but would
  100.    probably be much less readable as a result. */
  101. /* the way this is coded now is fairly naieve:  just try each of the
  102.    possibilities in turn,  with each succesive attempt representing one that
  103.    will yield a greater number of labels than the previous try.  As soon as
  104.    we pass maxlab, we return the previous try */
  105. int
  106. opt_div(order, maxlab, range)
  107.     int       order, maxlab, range;
  108. {
  109.     int       delta;        /* the delta we are trying */
  110.  
  111.     /* try a half-decade of the next order up */
  112.     delta = (order * 10) / 2;
  113.     if (max_fit(delta, range) > maxlab) {
  114.     /* couldn't even do half-decades of the next order of magnitude up. */
  115.     /* return an error */
  116.     return -1;
  117.     }
  118.     /* try twentades of the next order up */
  119.     delta = (order * 10) / 5;
  120.     if (max_fit(delta, range) > maxlab) {
  121.     delta = (order * 10) / 2;
  122.     return delta;
  123.     }
  124.     /* try decades of order */
  125.     delta = order;
  126.     if (max_fit(delta, range) > maxlab) {
  127.     delta = (order * 10) / 5;
  128.     return delta;
  129.     }
  130.     /* check if (order==1).  If so, we can't subdivide more than that. */
  131.     if (order == 1) {
  132.     return delta;
  133.     }
  134.     /* try half-decades of order */
  135.     delta = order / 2;
  136.     if (max_fit(delta, range) > maxlab) {
  137.     delta = order;
  138.     return delta;
  139.     }
  140.     /* and last, try twentades of order */
  141.     delta = order / 5;
  142.     if (max_fit(delta, range) > maxlab) {
  143.     delta = order / 2;
  144.     return delta;
  145.     } else {
  146.     /* twentades worked */
  147.     return delta;
  148.     }
  149. }
  150.  
  151. /* max_fit() -- the max number of labels of size delta which can fit in the
  152.    given range. */
  153. int
  154. max_fit(delta, range)
  155.     int       delta, range;
  156. {
  157.     return range / delta;
  158. }
  159.  
  160. /* lmult() -- lowest multiple of delta which is larger than min */
  161. int
  162. lmult(delta, min)
  163.     int       delta, min;
  164. {
  165.     return (min / delta + 1) * delta;
  166. }
  167.  
  168. /* hmult() -- highest multiple of delta which is less than max */
  169. int 
  170. hmult(delta, max)
  171.     int       delta, max;
  172. {
  173.     if ((max % delta) == 0) {    /* divides evenly */
  174.     return (max / delta - 1) * delta;
  175.     }
  176.     /* otherwise natural truncation from integer divides will do the trick */
  177.     return (max / delta) * delta;
  178. }
  179.  
  180. /* glab_db() -- debug a graph label vector, when passed a vector of
  181.  * graph_lab structures and the number of indices.
  182.  */
  183. glab_db(lvec, len)
  184.     struct graph_lab *lvec;
  185.     int       len;
  186. {
  187.     int       i;
  188.  
  189.     for (i = 0; i < len; i++) {
  190.     fprintf(stderr, "Value:%d, Label:%s, pixel offset: %d\n", lvec[i].val,
  191.         lvec[i].lab, lvec[i].p_off);
  192.     }
  193. }
  194.